package com.itjoin.pro_netty.ch1_2;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {
    public static void main(String[] args) throws Exception {
        start();
    }

    public static void start() {
        /**
         * 新建两个线程组，boss线程组启动一条线程监听OP_ACCEPT事件，
         * worker线程组默认启动cpu核数*2的线程,监听客户端连接
         * 的OP_READ和OP_WRITE事件,处理IO事件
         */
        EventLoopGroup bossGroup = new NioEventLoopGroup(0);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            // ServerBootstrap为netty服务启动辅助类
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup);
            // 设置TCP socket通道为NioServerSocketChannel，
            // 假如是UDP通信的话，则设置为DatagramChannel
            serverBootstrap.channel(NioServerSocketChannel.class);
            //设置一些TCP参数
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 2048)
                    /**
                     * 当有客户端链路注册读写事件时，初始化Handler， 并把handler加入到管道中
                     */
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            /**
                             * 往worker线程的管道双向链表中添加处理类ServerHandler,
                             * 整个处理流向：
                             * HeadContext-channelRead读数据-->ServerHandler-
                             * channelRead读取数据做业务逻辑判断，
                             * 最后写回结果给客户端-->TailContext-write->HeadContext-write
                             */
                            ch.pipeline().addLast(new ServerHandler());
                        }
                    });
            // 同步绑定端口
            ChannelFuture future = serverBootstrap.bind(8080).sync();
            // 阻塞主线程，直到socket通道被关闭
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 最终关闭线程组
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
}
